/*
 * Copyright 2025 arisgo@163.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.arisgo.cloud.flux.mybatis.search.page;

import java.io.Serializable;
import java.util.Collections;
import java.util.List;

/**
 * @author Coulson
 * @since 2023-08-30
 */
public class Pagination<T> implements Serializable {

    public static final int DEFAULT_PAGE = 0;
    public static final int DEFAULT_PAGE_SIZE = 10;

    private List<T> records;
    private long pageNo;
    private long pageSize;
    private long totalPages;
    private long totalCount;

    private Pagination(long pageNo, long pageSize, long totalPages, long totalCount, List<T> records) {
        this.pageNo = pageNo;
        this.pageSize = pageSize;
        this.totalPages = totalPages;
        this.totalCount = totalCount;
        this.records = records;
    }

    public List<T> getRecords() {
        return records;
    }

    public void setRecords(List<T> records) {
        this.records = records;
    }

    public long getPageNo() {
        return pageNo;
    }

    public void setPageNo(int pageNo) {
        this.pageNo = pageNo;
    }

    public long getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }

    public long getTotalPages() {
        return totalPages;
    }

    public void setTotalPages(int totalPages) {
        this.totalPages = totalPages;
    }

    public long getTotalCount() {
        return totalCount;
    }

    public void setTotalCount(long totalCount) {
        this.totalCount = totalCount;
    }

    public static class Builder<T> {

        private List<T> data;
        private long pageNo;
        private long pageSize;
        private long totalCount;
        private long totalPages;

        public Builder<T> data(List<T> data) {
            this.data = data;
            return this;
        }

        public Builder<T> pageNo(long page) {
            this.pageNo = page;
            return this;
        }

        public Builder<T> pageSize(long pageSize) {
            this.pageSize = pageSize;
            return this;
        }

        public Builder<T> totalPages(long totalPages) {
            this.totalPages = totalPages;
            return this;
        }

        public Builder<T> totalCount(long totalCount) {
            this.totalCount = totalCount;
            return this;
        }

        public Pagination<T> build() {
            return new Pagination<T>(this.pageNo, this.pageSize, this.totalPages, this.totalCount, this.data);
        }

        public Pagination<T> buildDefaultPage() {
            return new Pagination<T>(DEFAULT_PAGE, DEFAULT_PAGE_SIZE, 0, 0, Collections.emptyList());
        }
    }

    /**
     * 首页从 1 开始
     *
     * @param pageNo   当前页
     * @param pageSize 每页数量
     * @param data     数据
     */
    public static <T> Pagination<T> paging(long pageNo, long pageSize, List<T> data) {
        if (null == data || data.isEmpty()) {
            return new Builder<T>().buildDefaultPage();
        }
        if (pageNo < 1) {
            throw new RuntimeException("分页参数从 1 开始！");
        }
        long totalCount = data.size();
        long totalPages = totalCount % pageSize == 0 ? totalCount / pageSize : totalCount / pageSize + 1;
        if (pageNo > totalPages) {
            return new Builder<T>().buildDefaultPage();
        }
        Long offset = (pageNo - 1) * pageSize;
        if (offset.compareTo(totalCount) > 0) {
            return new Builder<T>().buildDefaultPage();
        }

        Long end = offset + pageSize;
        if (end.compareTo(totalCount) > 0) {
            end = totalCount;
        }
        return new Builder<T>()
                .pageNo(pageNo)
                .pageSize(pageSize)
                .totalCount(totalCount)
                .totalPages(totalPages)
                .data(data.subList(offset.intValue(), end.intValue()))
                .build();
    }

}
